package com.imflea.zero.advice;


import com.github.jaemon.dinger.DingerSender;
import com.github.jaemon.dinger.core.entity.DingerRequest;
import com.github.jaemon.dinger.core.entity.enums.MessageSubType;
import com.imflea.zero.constants.ZeroContant;
import com.imflea.zero.exception.BizException;
import com.imflea.zero.exception.CustomIllegalArgumentException;
import com.imflea.zero.exception.MallServiceException;
import com.imflea.zero.util.base.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionToHandler {
//    private static final String INTERNAL_ERROR = "系统内部错误";



    @Autowired
    private DingerSender dingerSender;


    @ExceptionHandler(value = {MallServiceException.class, BizException.class, CustomIllegalArgumentException.class})
    public JsonResult<String> customExceptionHandler(Exception e) {
        log.error(e.getMessage());
        dingerSender.send(MessageSubType.TEXT, DingerRequest.request("异常信息监控："+e.getMessage(), "监控"));
        return new JsonResult<>(ZeroContant.getFailCode(), e.getMessage(), null);
    }

    /**
     * 用来处理bean validation异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public JsonResult<String> resolveConstraintViolationException(ConstraintViolationException ex) {
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        if (!CollectionUtils.isEmpty(constraintViolations)) {
            StringBuilder msgBuilder = new StringBuilder();
            for (ConstraintViolation<?> constraintViolation : constraintViolations) {
                msgBuilder.append(constraintViolation.getMessage()).append(",");
            }
            String errorMessage = msgBuilder.toString();
            if (errorMessage.length() > 1) {
                errorMessage = errorMessage.substring(0, errorMessage.length() - 1);
            }

            return new JsonResult<>(ZeroContant.getFailCode(), errorMessage);
        }
        return new JsonResult<>(ZeroContant.getFailCode(), ex.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public JsonResult<String> resolveMethodArgumentNotValidException(MethodArgumentNotValidException ex) {

        List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors();
        if (!CollectionUtils.isEmpty(objectErrors)) {
            StringBuilder msgBuilder = new StringBuilder();
            for (ObjectError objectError : objectErrors) {
                msgBuilder.append(objectError.getDefaultMessage()).append(",");
            }
            String errorMessage = msgBuilder.toString();
            if (errorMessage.length() > 1) {
                errorMessage = errorMessage.substring(0, errorMessage.length() - 1);
            }
            return new JsonResult<>(ZeroContant.getFailCode(), errorMessage);
        }
        return new JsonResult<>(ZeroContant.getFailCode(), ex.getMessage());
    }


//    @ExceptionHandler(HttpMessageNotReadableException.class)
//    @ResponseBody
//    public JsonResult<String> resolveBeanTimeBindException(HttpMessageNotReadableException ex) {
//        StackTraceElement[] stacks = ex.getCause().getStackTrace();
//        String detailMsg = ex.getMessage();
//        if (detailMsg.contains("yyyy-MM-dd")) {
//            return new JsonResult<>(ZeroContant.getFailCode(), "请求的参数异常:可能有时间或日期输入格式错误！");
//        }
//
//        for (int i = 0; i < stacks.length; i++) {
//            logger.error(stacks[i].getClassName());
//        }
//        return new JsonResult<>(ZeroContant.getFailCode(), "请求的参数异常:请检查录入的数据中时间，日期和数字是否为正确的内容！若无法自行排除问题，请联系运维人员");
//    }


//    @ExceptionHandler(value = RuntimeException.class)
//    public JsonResult<String> runTimeErrorHandler(Exception ex) {
//        final StringWriter sw = new StringWriter();
//        final PrintWriter pw = new PrintWriter(sw);
//        try {
//            ex.printStackTrace();
//            ex.printStackTrace(pw);
//            return new JsonResult<>(ZeroContant.getFailCode(), INTERNAL_ERROR);
//        } finally {
//            pw.close();
//        }
//
//    }

    // 应该是不生效
    @ExceptionHandler(value = SQLException.class)
    public JsonResult<String> handleSqlException(HttpServletRequest request, SQLException ex) {
        log.error(ex.getMessage());
        final StringWriter sw = new StringWriter();
        final PrintWriter pw = new PrintWriter(sw);
        try {
            ex.printStackTrace();
            ex.printStackTrace(pw);
            return new JsonResult<>(ZeroContant.getFailCode(), ex.getMessage());
        } finally {
            pw.close();
        }

    }

    @ExceptionHandler(value = DataAccessException.class)
    public JsonResult<String> runTimeErrorHandler(HttpServletRequest request, DataAccessException ex) {
        log.error(ex.getMessage());
        final StringWriter sw = new StringWriter();
        final PrintWriter pw = new PrintWriter(sw);
        try {
            ex.printStackTrace();
            ex.printStackTrace(pw);
            return new JsonResult<>(ZeroContant.getFailCode(), ex.getMessage());
        } finally {
            pw.close();
        }
    }

    // 应该加一个兜底的异常处理。并记录日志信息
    @ExceptionHandler(Exception.class)
    public JsonResult<String> defaultHandler(Exception e) {
        log.error(e.getMessage());
        e.printStackTrace();
        return new JsonResult<>(ZeroContant.getFailCode(), e.getMessage(), null);
    }
}

